package com.trs.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@SuppressWarnings("unchecked")
public class HttpClientUtil {
	// private static log log = logFactory.getlog(HttpClientUtil.class);

	public static void main(String[] args) {
		try {
			System.err.println(HttpClientUtil.getCode("http://10.110.76.101/govapp/#/mg/channelmg/websiteapp/recycle?mgtype=website"));
			System.err.println(HttpClientUtil.getCode("http://10.11.2.147:8099/rmHtml"));
			System.err.println(HttpClientUtil.getCode("https://www.cq.gov.cn/ywdt/jrcq/202310/t20231026_124736531.html"));
			System.err.println(HttpClientUtil.getCode("http://10.110.76.102/govapp/#/mg/channelmg/websiteapp/recycle?mgtype=website"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private volatile static CloseableHttpClient httpClient;

	private HttpClientUtil() {
	}

	private static CloseableHttpClient getHttpClient() {
		if (httpClient == null) {
			synchronized (HttpClientUtil.class) {
				if (httpClient == null) {
					httpClient = HttpPoolConManager.getClient();
				}
			}
		}
		return httpClient;
	}

	/**
	 * 自定义配置方式初使化httpclient 此方法在一个应用系统里面，只需要执行一次。 应用程序自行控制。
	 * 
	 * @param config
	 */
	public static void config1(HttpClientConfig config) {
		if (httpClient != null) {
			log.warn("http client already init ! ");
		}
		httpClient = HttpPoolConManager.getClient(config);
	}

	/**
	 * 发送get请求
	 * 
	 * @param url
	 *            请求地址
	 * @return 返回请求结果
	 * @throws Exception
	 */
	public static String get(String url) throws Exception {
		return get(url, Collections.EMPTY_MAP);
	}

	/**
	 * 发送get请求
	 * 
	 * @param url
	 *            请求地址
	 * @return 返回请求结果
	 * @throws Exception
	 */
	public static int getCode(String url) throws Exception {
		HttpGet httpGet = new HttpGet(url);
		return response(httpGet);
	}

	/**
	 * 发送get请求
	 * 
	 * @param url
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @return
	 * @throws Exception
	 */
	public static String get(String url, Map<String, String> params) throws Exception {
		return get(url, Collections.EMPTY_MAP, params);
	}

	/**
	 * 发送get请求
	 * 
	 * @param url
	 *            请求地址
	 * @param headers
	 *            请求头
	 * @param params
	 *            请求参数
	 * @return
	 * @throws IOException
	 */
	public static String get(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
		// *) 构建GET请求头
		String apiUrl = appendQueryParams(url, params);
		HttpGet httpGet = new HttpGet(apiUrl);
		return response(httpGet, headers);
	}

	/**
	 * 发送post请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @return 请求结果
	 */
	public static String post(String apiUrl) throws Exception {
		return post(apiUrl, Collections.EMPTY_MAP);
	}

	/**
	 * 发送post请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @return 请求结果
	 */
	public static String post(String apiUrl, Map<String, Object> params) throws Exception {
		return post(apiUrl, Collections.EMPTY_MAP, params);
	}

	/**
	 * 发送post请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @param headers
	 *            header
	 * @param params
	 *            请求参数
	 * @return 返回参数
	 * @throws IOException
	 */
	public static String post(String apiUrl, Map<String, String> headers, Map<String, Object> params) throws Exception {

		if (params.containsKey("serviceid")) {
			String serviceid = ((String) params.get("serviceid")).toLowerCase();
			if (serviceid.indexOf("wcm6_document") > -1 || serviceid.indexOf("wcm6_metadatacenter") > -1 || serviceid.startsWith("meiti")) {
				apiUrl += "/wcm/govcenter.do";
			} else if (serviceid.startsWith("rb")) {
				apiUrl += "/wcm/opendata.do";
			} else {
				apiUrl += "/gov/opendata.do";
			}
			params.put("serviceid", serviceid.replace("meiti", "").replace("rb", ""));
		}

		log.info("请求地址 : {} 请求参数 : {}", apiUrl, params);
		HttpPost httpPost = new HttpPost(apiUrl);

		// *) 配置请求参数
		if (params != null && params.size() > 0) {
			HttpEntity entityReq = getUrlEncodedFormEntity(params);
			httpPost.setEntity(entityReq);
		}

		return response(httpPost, headers);
	}

	/**
	 * 发送post请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @param headers
	 *            header
	 * @param params
	 *            请求参数
	 * @return 返回参数
	 * @throws IOException
	 */
	public static String post1(String apiUrl, Map<String, String> headers, Map<String, ContentBody> params) throws Exception {

		MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
		for (Entry<String, ContentBody> param : params.entrySet()) {
			multipartEntityBuilder.addPart(param.getKey(), param.getValue());
		}

		// 解决中文乱码
		// multipartEntityBuilder.setCharset(StandardCharsets.UTF_8);
		multipartEntityBuilder.setMode(HttpMultipartMode.RFC6532);

		log.debug("请求地址 : {} 请求参数 : {}", apiUrl, params);
		HttpPost httpPost = new HttpPost(apiUrl);
		HttpEntity reqEntity = multipartEntityBuilder.build();
		httpPost.setEntity(reqEntity);
		httpPost.addHeader("Expect", "100-continue");
		return response(httpPost, headers);
	}

	/**
	 * 发送post请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @param headers
	 *            header
	 * @param params
	 *            请求参数
	 * @return 返回参数
	 * @throws IOException
	 */
	public static String post(String apiUrl, File file, Map<String, String> headers) throws Exception {
		HttpPost httpPost = new HttpPost(apiUrl);
		httpPost.setEntity(new InputStreamEntity(new FileInputStream(file)));
		return response(httpPost, headers);
	}

	/**
	 * 发送post请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @param headers
	 *            header
	 * @param params
	 *            请求参数
	 * @return 返回参数
	 * @throws IOException
	 */
	public static String post(String apiUrl, byte[] file, Map<String, String> headers) throws Exception {
		HttpPost httpPost = new HttpPost(apiUrl);
		httpPost.setEntity(new InputStreamEntity(new ByteArrayInputStream(file)));
		return response(httpPost, headers);
	}

	/**
	 * 发送post请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @param headers
	 *            header
	 * @param params
	 *            请求参数
	 * @return 返回参数
	 * @throws IOException
	 */
	public static CloseableHttpResponse post(String apiUrl, Map<String, String> headers, File file) throws Exception {

		HttpPost httpPost = new HttpPost(apiUrl);
		httpPost.setEntity(new InputStreamEntity(new FileInputStream(file)));

		// *) 设置header信息
		if (headers != null && headers.size() > 0) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				httpPost.addHeader(entry.getKey(), entry.getValue());
			}
		}

		return getHttpClient().execute(httpPost);
	}

	/**
	 * 发送post请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @param params
	 *            请求参数
	 * @return 请求结果
	 */
	public static String postJson(String apiUrl, String params) throws Exception {
		return postJson(apiUrl, Collections.EMPTY_MAP, params);
	}

	/**
	 * 发送post json 请求
	 * 
	 * @param apiUrl
	 *            请求地址
	 * @param headers
	 *            请求头
	 * @param body
	 *            请求json内容
	 * @return 返回请求结果
	 * @throws IOException
	 */
	public static String postJson(String apiUrl, Map<String, String> headers, String body) throws Exception {

		HttpPost httpPost = new HttpPost(apiUrl);
		httpPost.addHeader("Content-Type", "application/json");

		// *) 配置请求参数
		if (body != null && !"".equals(body)) {
			HttpEntity entityReq = new StringEntity(body, "UTF-8");
			httpPost.setEntity(entityReq);
		}

		return response(httpPost, headers);
	}

	/**
	 * 将参数转为httpEntity实体。
	 * 
	 * @param params
	 *            请求参数
	 * @return
	 */
	private static HttpEntity getUrlEncodedFormEntity(Map<String, Object> params) {
		List<NameValuePair> pairList = new ArrayList<>(params.size());
		for (Map.Entry<String, Object> entry : params.entrySet()) {
			NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue() + "");
			pairList.add(pair);
		}
		return new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8"));
	}

	/**
	 * @param request
	 *            请求方式
	 * @param headers
	 *            请求头
	 * @return 返回请求结果
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	private static String response(HttpRequestBase request, Map<String, String> headers) throws Exception {
		if (request.getURI().toString().indexOf("govcenter.do") > 0 || request.getURI().toString().indexOf("opendata.do") > 0) {
			request.addHeader("formdata", "1");
		}
		if (headers != null && headers.size() > 0) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				request.addHeader(entry.getKey(), entry.getValue());
			}
		}

		try (CloseableHttpResponse response = getHttpClient().execute(request)) {
			if (response == null || response.getStatusLine() == null) {
				throw new Exception("访问异常 : " + request.getURI());
			}
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				HttpEntity entityRes = response.getEntity();
				if (entityRes != null) {
					return EntityUtils.toString(entityRes, "UTF-8");
				}
			} else {
				throw new Exception("访问异常 : " + request.getURI() + " : " + response.getStatusLine().getStatusCode());
			}
			return "";
		} catch (IllegalStateException e) {
			if (e.getMessage().indexOf("Connection pool shut down") > -1) {
				log.error("请求连接池异常，尝试重新初始化", e);
				httpClient = null;
				return response(request, headers);
			} else {
				throw e;
			}
		}

	}

	/**
	 * @param request
	 *            请求方式
	 * @param headers
	 *            请求头
	 * @return 返回状态码：一般见到的就是200 3开头的表示重定向 301永久重定向 302临时重定向 304表示可以在缓存中取数据(协商缓存) 4开头表示客户端错误 403跨域 404请求资源不存在 5开头表示服务端错误 500
	 */
	private static int response(HttpRequestBase request) throws Exception {
		try {
			CloseableHttpResponse response = getHttpClient().execute(request);
			if (response == null || response.getStatusLine() == null) {
				throw new Exception("访问异常 : " + request.getURI());
			}
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && response.containsHeader("Location") && !Util.isNull(response.getHeaders("Location")[0]) && response.getHeaders("Location")[0].toString().toLowerCase().indexOf(request.getURI().toString().toLowerCase().replace("http", "")) > -1) {
				return 200;
			} else {
				return response.getStatusLine().getStatusCode();
			}
		} catch (Exception e) {
			e.printStackTrace();
			return 400;
		}
	}

	/**
	 * Append query parameters to given url
	 * 
	 * @param url
	 *            Url as string
	 * @param params
	 *            Map with query parameters
	 * @return url Url with query parameters appended
	 * @throws IOException
	 */
	static public String appendQueryParams(String url, Map<String, String> params) throws IOException {
		String fullUrl = url;
		if (params != null) {
			boolean first = (fullUrl.indexOf('?') == -1);
			for (String param : params.keySet()) {
				if (first) {
					fullUrl += '?';
					first = false;
				} else {
					fullUrl += '&';
				}
				String value = params.get(param);
				fullUrl += URLEncoder.encode(value, "UTF-8");
			}
		}

		return fullUrl;
	}
}
